<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.7: http://docutils.sourceforge.net/" />
<title>Trestle: doctest for REST(ful services)</title>
<style type="text/css">

/*
:Author: David Goodger
:Contact: goodger@users.sourceforge.net
:Date: $Date: 2005-12-18 01:56:14 +0100 (Sun, 18 Dec 2005) $
:Revision: $Revision: 4224 $
:Copyright: This stylesheet has been placed in the public domain.

Default cascading style sheet for the HTML output of Docutils.

See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
customize this style sheet.
*/

body { 
  font-family: verdana, arial, sans-serif;
  font-size: small;
  padding-right: 5em;
 }

/* used to remove borders from tables and images */
.borderless, table.borderless td, table.borderless th {
  border: 0 }

table.borderless td, table.borderless th {
  /* Override padding for "table.docutils td" with "! important".
     The right padding separates the table cells. */
  padding: 0 0.5em 0 0 ! important }

.first {
  /* Override more specific margin styles with "! important". */
  margin-top: 0 ! important }

.last, .with-subtitle {
  margin-bottom: 0 ! important }

.hidden {
  display: none }

a.toc-backref {
  text-decoration: none ;
  color: black }

blockquote.epigraph {
  margin: 2em 5em ; }

dl.docutils dd {
  margin-bottom: 0.5em }

dl.docutils dt {
  font-weight: bold }

div.abstract {
  margin: 2em 5em }

div.abstract p.topic-title {
  font-weight: bold ;
  text-align: center }

div.admonition, div.attention, div.caution, div.danger, div.error,
div.hint, div.important, div.note, div.tip, div.warning {
  margin: 2em ;
  border: medium outset ;
  padding: 1em }

div.admonition p.admonition-title, div.hint p.admonition-title,
div.important p.admonition-title, div.note p.admonition-title,
div.tip p.admonition-title {
  font-weight: bold ;
  font-family: sans-serif }

div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title {
  color: red ;
  font-weight: bold ;
  font-family: sans-serif }

div.compound .compound-first, div.compound .compound-middle {
  margin-bottom: 0.5em }

div.compound .compound-last, div.compound .compound-middle {
  margin-top: 0.5em }

div.dedication {
  margin: 2em 5em ;
  text-align: center ;
  font-style: italic }

div.dedication p.topic-title {
  font-weight: bold ;
  font-style: normal }

div.figure {
  margin-left: 2em ;
  margin-right: 2em }

div.footer, div.header {
  clear: both;
  font-size: smaller }

div.line-block {
  display: block ;
  margin-top: 1em ;
  margin-bottom: 1em }

div.line-block div.line-block {
  margin-top: 0 ;
  margin-bottom: 0 ;
  margin-left: 1.5em }

div.sidebar {
  margin-left: 1em ;
  border: medium outset ;
  padding: 1em ;
  background-color: #ffffee ;
  width: 40% ;
  float: right ;
  clear: right }

div.sidebar p.rubric {
  font-family: sans-serif ;
  font-size: medium }

div.system-messages {
  margin: 5em }

div.system-messages h1 {
  color: red }

div.system-message {
  border: medium outset ;
  padding: 1em }

div.system-message p.system-message-title {
  color: red ;
  font-weight: bold }

div.topic {
  margin: 2em }

h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
  margin-top: 0.4em }

h1.title {
  text-align: center }

h2.subtitle {
  text-align: center }

hr.docutils {
  width: 75% }

img.align-left {
  clear: left }

img.align-right {
  clear: right }

ol.simple, ul.simple {
  margin-bottom: 1em }

ol.arabic {
  list-style: decimal }

ol.loweralpha {
  list-style: lower-alpha }

ol.upperalpha {
  list-style: upper-alpha }

ol.lowerroman {
  list-style: lower-roman }

ol.upperroman {
  list-style: upper-roman }

p.attribution {
  text-align: right ;
  margin-left: 50% }

p.caption {
  font-style: italic ;
  color: #aaa;
  margin-top: -6px;
  padding-top: 0px;
  margin-left: 2em;
  font-size: smaller;
}

p.credits {
  font-style: italic ;
  font-size: smaller }

p.label {
  white-space: nowrap }

p.rubric {
  font-weight: bold ;
  font-size: larger ;
  color: maroon ;
  text-align: center }

p.sidebar-title {
  font-family: sans-serif ;
  font-weight: bold ;
  font-size: larger }

p.sidebar-subtitle {
  font-family: sans-serif ;
  font-weight: bold }

p.topic-title {
  font-weight: bold }

pre.address {
  margin-bottom: 0 ;
  margin-top: 0 ;
  font-family: serif ;
  font-size: 100% }

pre.literal-block, pre.doctest-block {
  margin-left: 2em ;
  margin-right: 2em ;
  background-color: #eeeeee }

span.classifier {
  font-family: sans-serif ;
  font-style: oblique }

span.classifier-delimiter {
  font-family: sans-serif ;
  font-weight: bold }

span.interpreted {
  font-family: sans-serif }

span.option {
  white-space: nowrap }

span.pre {
  white-space: pre }

span.problematic {
  color: red }

span.section-subtitle {
  /* font-size relative to parent (h1..h6 element) */
  font-size: 80% }

table.citation {
  border-left: solid 1px gray;
  margin-left: 1px }

table.docinfo {
  margin: 2em 4em }

table.docutils {
  margin-top: 0.5em ;
  margin-bottom: 0.5em }

table.footnote {
  border-left: solid 1px black;
  margin-left: 1px }

table.docutils td, table.docutils th,
table.docinfo td, table.docinfo th {
  padding-left: 0.5em ;
  padding-right: 0.5em ;
  vertical-align: top }

table.docutils th.field-name, table.docinfo th.docinfo-name {
  font-weight: bold ;
  text-align: left ;
  white-space: nowrap ;
  padding-left: 0 }

h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
  font-size: 100% }

tt.docutils {
  background-color: #eeeeee }

ul.auto-toc {
  list-style-type: none }

pre.response.pass, .pass
{ 
  background: #dfd; !important
 }

pre.response.fail, .fail
{ 
  background: #faa; !important
}

li.fail
{ 
  background: #fff;
}

li.fail a
{ 
  color: #f55;
  font-weight: bold;
}

tt.request.method
{ 
  font-weight: bold;
}

.contents
{ 
  float: right;
  font-size: smaller;
  border: 1px solid #ddd;
  padding-left: 1em;
  padding-right: 1em;
}

.contents ul
{ 
  padding-left: 1em;
  margin-right: .5em;
  margin-left: 0;
}

.contents p.topic-title
{ 
  padding-top: 1ex;
}

</style>
</head>
<body>
<div class="document" id="trestle-doctest-for-rest-ful-services">
<h1 class="title">Trestle: doctest for REST(ful services)</h1>

<div class="contents topic" id="contents">
<p class="topic-title first">Contents</p>
<ul class="simple">
<li><a class="reference internal" href="#about" id="id1">About</a><ul>
<li><a class="reference internal" href="#trestle-directives" id="id2">Trestle directives</a></li>
<li><a class="reference internal" href="#fixture-commands" id="id3">Fixture commands</a></li>
<li><a class="reference internal" href="#shell-examples" id="id4">Shell examples</a></li>
</ul>
</li>
<li><a class="reference internal" href="#examples" id="id5">Examples</a></li>
<li><a class="reference internal" href="#source" id="id6">Source</a></li>
</ul>
</div>
<div class="section" id="about">
<h1><a class="toc-backref" href="#id1">About</a></h1>
<p>Trestle is a nose plugin that enables you to write testable documentation for
web apps (or shell commands, but more on that later).</p>
<p>To use trestle, write a <a class="reference external" href="http://docutils.sourceforge.net/rst.html">reStructured Text</a> document (like this one) using a
set of special directives to indicate the <strong>fixtures</strong> to be used for testing
(including the http or mock http client), each <strong>request</strong> to be sent via the
client, and the <strong>expected response</strong> from the application under test.</p>
<p>A simple trestle test document might look like this:</p>
<pre class="literal-block">
Frog: A web service for doing things with frogs
-----------------------------------------------

.. fixtures :: frog_fixtures

Frog is a web service for doing things with frogs.

You can list the available frogs.

.. request :: List available frogs

   GET /frogs
..

The response is in a plain-text format.

.. response ::

   bullfrog
   poison dart
   treefrog
   ...
..

You can find out if something is a frog.

.. request :: Get bullfrog details

   GET /frogs/bullfrog
..

If the requested term is a frog, details about the frog will be returned.

.. response ::

   Bullfrogs are really big frogs.
..

Otherwise, a 404 response is returned.

.. request :: Get details for a non-frog

   GET /frogs/toad
..

.. response ::

   404 ...
   ...

   &quot;toad&quot; is not a frog.
..

You can create frogs.

.. request :: Create a frog

   POST /frogs/pouched+frog
   A pouched frog camouflages itself to look like dead leaves.
..

.. response ::

   201 Created
   ...

   ...
..
</pre>
<div class="section" id="trestle-directives">
<h2><a class="toc-backref" href="#id2">Trestle directives</a></h2>
<p>Fixtures for a trestle test file are set like so:</p>
<pre class="literal-block">
.. fixtures:: about
</pre>
<p>A fixtures directive is required in every document to be tested. The
directive must name a python module. The module must include the
following attribute:</p>
<dl class="docutils">
<dt>client</dt>
<dd>A client application to be called with methods .get(), .post(),
.put(), etc. Each method must accept at least the arguments url and
data, and may accept others but may not require
them. <a class="reference external" href="http://pythonpaste.org/testing-applications.html">paste.fixtures.TestApp</a> is such a client, though it natively
supports only .get() and .post().</dd>
</dl>
<p>And may include the following functions:</p>
<dl class="docutils">
<dt>setup_all(cls)</dt>
<dd>Setup fixture run before the first request.</dd>
<dt>teardown_all(cls)</dt>
<dd>Teardown fixture run after the last request.</dd>
<dt>setup_each(inst)</dt>
<dd>Setup fixture run before each request.</dd>
<dt>teardown_each(inst)</dt>
<dd>Teardown fixture run after each request.</dd>
</dl>
<p>Tests in a trestle document consist of a <tt class="docutils literal">.. request</tt> directive, followed by
one or more <tt class="docutils literal">.. response</tt> directives. The <tt class="docutils literal">.. request</tt> directive defines
the request to be sent to the web app under test, using the client defined in
the fixtures module.</p>
<p>A simple request directive looks like this:</p>
<pre class="literal-block">
.. request:: A simple get

  GET /foo/bar
..
</pre>
<p>If the request is a POST or PUT that includes data to be sent, include
that data in the body of the request, after the request line:</p>
<pre class="literal-block">
.. request:: A post

  POST /foo/bar
  a=1&amp;b=2
..
</pre>
<p>The response expected to be returned to the client is defined using a
response block:</p>
<pre class="literal-block">
.. response::

  Ponies!!1!
..
</pre>
<div class="note">
<p class="first admonition-title">Note</p>
<p class="last">Conclude each block with <tt class="docutils literal">..</tt> alone on a line to avoid rst parsing
errors that can result in text following a block being thrown away.</p>
</div>
<p>The testing process is simple: each request is executed using the
client defined in the fixtures module, and each expected response
following that request in the text is compared against the actual
response. If all responses match, the test passes. Otherwise, it
fails.</p>
<p>Passing examples are given a <span class="pass">pleasing green
   background</span>, failures a <span class="fail">sinister red</span>.
   Details of the failed match are included following the
   failed example.</p></div>
<div class="section" id="fixture-commands">
<h2><a class="toc-backref" href="#id3">Fixture commands</a></h2>
<p>At times it may be necessary to execute a unique fixture before executing a
request. While it's usually better to make the test depend only on public apis
and not internal details or externalities, sometimes (e.g. when testing
time-dependent operations) that isn't possible or reasonable. For those times,
use the <strong>:setup:</strong> argument to the request. The body of the exec argument
will be evaluated in the context of the fixture module before running the
request. Naturally, there is also a <strong>:teardown:</strong> argument, which will be
executed after the request is run and the response processed. Here's an
example:</p>
<pre class="literal-block">
.. request:: Get something special
   :setup: client.set_special(true)
   :teardown: client.set_special(false)

   GET /special
..
</pre>
</div>
<div class="section" id="shell-examples">
<h2><a class="toc-backref" href="#id4">Shell examples</a></h2>
<p>Trestle also supports shell examples. When a shell example is executed, the
shell command given is executed, and the stdout produced by the command is
compared to the body of the <tt class="docutils literal">..shell</tt> example using the normal doctest
output checker. A simple shell example looks like this:</p>
<pre class="literal-block">
.. shell :: echo &quot;Hello&quot;

   Hello
..
</pre>
<p>Shell examples support the standard <tt class="docutils literal">:setup:</tt> and <tt class="docutils literal">:teardown</tt> options, as
well as three others: <tt class="docutils literal">:cwd:</tt>, which can be used to set the cwd of the shell
command; <tt class="docutils literal">:post:</tt>, which names a fixture callable to be used to post-process
the output of the shell command before checking it against the expected
output, and the flag <tt class="docutils literal">:stderr:</tt>, which indicates that the example output
should be compared against the stderr output of the shell command, rather than
stdout (which is the default).</p>
</div>
</div>
<div class="section" id="examples">
<h1><a class="toc-backref" href="#id5">Examples</a></h1>
<p>The application used by this self test is very simple: it always replies with
'Hello' to GET requests, unless <strong>special</strong> mode is active. Let's start the
test examples with a simple GET request.</p>
<pre class="literal-block">
<tt class="request method docutils literal">GET</tt> <tt class="request url docutils literal">/foo</tt>
</pre>
<p class="caption">A simple get</p>
<p>You can match on the whole response -- be sure to always include both
the full status line and headers:</p>
<pre class="response pass literal-block">
200 Ok
Content-type: text/plain

Hello
</pre>
<!--  -->
<p>Or just the content. Notice that multiple response blocks can be
compared against the same request.</p>
<pre class="response pass literal-block">
Hello
</pre>
<!--  -->
<p>The output comparison is done using a doctest OutputChecker. The
doctest extensions NORMALIZE_WHITESPACE and ELLIPSIS are always on, so
this response also matches:</p>
<pre class="response pass literal-block">
200 ...
...

He...o
</pre>
<!--  -->
<hr class="docutils" />
<p>POST requests include the data to be posted after the request line.</p>
<pre class="literal-block">
<tt class="request method docutils literal">POST</tt> <tt class="request url docutils literal">/foo</tt>

a=1&amp;b=2
</pre>
<p class="caption">A simple POST</p>
<p>The simple application used in this self test always responds to POST
requests by echoing back the posted parameters:</p>
<pre class="response pass literal-block">
You said: a=1 and b=2
</pre>
<!--  -->
<p>Just like with GETs, you can match against headers and content or content only.</p>
<pre class="response pass literal-block">
200 Ok
Content-type: text/plain

You said: a=1 and b=2
</pre>
<!--  -->
<hr class="docutils" />
<p>Fixture code may be run around a request.</p>
<pre class="literal-block">
<tt class="request method docutils literal">GET</tt> <tt class="request url docutils literal">/special</tt>
</pre>
<p class="caption">A special request requiring its own fixture.</p>
<pre class="response pass literal-block">
SPECIAL is set.
</pre>
<!--  -->
<pre class="literal-block">
<tt class="request method docutils literal">GET</tt> <tt class="request url docutils literal">/special</tt>
</pre>
<p class="caption">Without the fixture</p>
<pre class="response pass literal-block">
SPECIAL is not set.
</pre>
<!--  -->
<hr class="docutils" />
<p>A simple shell example.</p>
<pre class="literal-block">
<tt class="request method docutils literal">echo &quot;Hello&quot;</tt>
</pre>
<pre class="response pass literal-block">
Hello
</pre>
<!--  -->
</div>
<div class="section" id="source">
<h1><a class="toc-backref" href="#id6">Source</a></h1>
<p>Here is the source of the fixtures file used with this test:</p>
<pre class="literal-block">
from paste.fixture import TestApp
from cgi import parse_qsl

def app(environ, start_response):
    start_response('200 Ok', [('Content-type', 'text/plain')])

    if environ['REQUEST_METHOD'] == 'GET':
        return ['Hello']
    elif environ['REQUEST_METHOD'] == 'POST':
        post_data = str(environ['wsgi.input'].read())
        params = parse_qsl(post_data)
        return ['You said: ', 
                ' and '.join('%s=%s' % p for p in params)]

def setup_all(cls):
    pass

def teardown_all(cls):
    pass

def setup_each(inst):
    pass

def teardown_each(inst):
    pass


class SpecialTestApp(TestApp):
    special = False

    def get(self, url, *arg, **kw):
        if url == '/special':
            if self.special:
                r = &quot;SPECIAL is set.&quot;
            else:
                r = &quot;SPECIAL is not set.&quot;
            res = self._make_response(('200 OK', [], r, []), 0)
            return res
        return super(SpecialTestApp, self).get(url, *arg, **kw)
        
    def setup_special(self):
        self.special = True

    def teardown_special(self):
        self.special = False


client = SpecialTestApp(app)

</pre>
<p>And the source of the test document itself:</p>
<pre class="literal-block">
Trestle: doctest for REST(ful services)
---------------------------------------

.. fixtures:: about
.. contents::

About
~~~~~

Trestle is a nose plugin that enables you to write testable documentation for
web apps (or shell commands, but more on that later).

To use trestle, write a `reStructured Text`_ document (like this one) using a
set of special directives to indicate the **fixtures** to be used for testing
(including the http or mock http client), each **request** to be sent via the
client, and the **expected response** from the application under test.

A simple trestle test document might look like this::

  Frog: A web service for doing things with frogs
  -----------------------------------------------

  .. fixtures :: frog_fixtures

  Frog is a web service for doing things with frogs.
  
  You can list the available frogs. 
  
  .. request :: List available frogs

     GET /frogs
  ..

  The response is in a plain-text format.
  
  .. response ::
    
     bullfrog
     poison dart
     treefrog
     ...
  ..

  You can find out if something is a frog.

  .. request :: Get bullfrog details

     GET /frogs/bullfrog
  ..

  If the requested term is a frog, details about the frog will be returned.
  
  .. response ::

     Bullfrogs are really big frogs.
  ..

  Otherwise, a 404 response is returned.

  .. request :: Get details for a non-frog

     GET /frogs/toad
  ..

  .. response ::

     404 ...
     ...
     
     &quot;toad&quot; is not a frog.
  ..

  You can create frogs.

  .. request :: Create a frog

     POST /frogs/pouched+frog
     A pouched frog camouflages itself to look like dead leaves.
  ..

  .. response ::

     201 Created
     ...

     ...
  ..

Trestle directives
^^^^^^^^^^^^^^^^^^
  
Fixtures for a trestle test file are set like so::

  .. fixtures:: about

A fixtures directive is required in every document to be tested. The
directive must name a python module. The module must include the
following attribute:
  
client
  A client application to be called with methods .get(), .post(),
  .put(), etc. Each method must accept at least the arguments url and
  data, and may accept others but may not require
  them. `paste.fixtures.TestApp`_ is such a client, though it natively
  supports only .get() and .post().

And may include the following functions:

setup_all(cls)
  Setup fixture run before the first request.

teardown_all(cls)
  Teardown fixture run after the last request.

setup_each(inst)
  Setup fixture run before each request.

teardown_each(inst)
  Teardown fixture run after each request.

Tests in a trestle document consist of a ``.. request`` directive, followed by
one or more ``.. response`` directives. The ``.. request`` directive defines
the request to be sent to the web app under test, using the client defined in
the fixtures module.
  
A simple request directive looks like this::

  .. request:: A simple get

    GET /foo/bar
  ..

If the request is a POST or PUT that includes data to be sent, include
that data in the body of the request, after the request line::

  .. request:: A post

    POST /foo/bar
    a=1&amp;b=2
  ..

The response expected to be returned to the client is defined using a
response block::

  .. response::

    Ponies!!1!
  ..


.. note:: Conclude each block with ``..`` alone on a line to avoid rst parsing
          errors that can result in text following a block being thrown away.

The testing process is simple: each request is executed using the
client defined in the fixtures module, and each expected response
following that request in the text is compared against the actual
response. If all responses match, the test passes. Otherwise, it
fails.

.. raw:: html

  &lt;p&gt;Passing examples are given a &lt;span class=&quot;pass&quot;&gt;pleasing green 
     background&lt;/span&gt;, failures a &lt;span class=&quot;fail&quot;&gt;sinister red&lt;/span&gt;. 
     Details of the failed match are included following the
     failed example.&lt;/p&gt;


Fixture commands
^^^^^^^^^^^^^^^^

At times it may be necessary to execute a unique fixture before executing a
request. While it's usually better to make the test depend only on public apis
and not internal details or externalities, sometimes (e.g. when testing
time-dependent operations) that isn't possible or reasonable. For those times,
use the **:setup:** argument to the request. The body of the exec argument
will be evaluated in the context of the fixture module before running the
request. Naturally, there is also a **:teardown:** argument, which will be
executed after the request is run and the response processed. Here's an
example::

  .. request:: Get something special
     :setup: client.set_special(true)
     :teardown: client.set_special(false)

     GET /special
  ..

  
Shell examples
^^^^^^^^^^^^^^
  
Trestle also supports shell examples. When a shell example is executed, the
shell command given is executed, and the stdout produced by the command is
compared to the body of the ``..shell`` example using the normal doctest
output checker. A simple shell example looks like this::

 .. shell :: echo &quot;Hello&quot;

    Hello
 ..

Shell examples support the standard ``:setup:`` and ``:teardown`` options, as
well as three others: ``:cwd:``, which can be used to set the cwd of the shell
command; ``:post:``, which names a fixture callable to be used to post-process
the output of the shell command before checking it against the expected
output, and the flag ``:stderr:``, which indicates that the example output
should be compared against the stderr output of the shell command, rather than
stdout (which is the default).
 
Examples
~~~~~~~~

The application used by this self test is very simple: it always replies with
'Hello' to GET requests, unless **special** mode is active. Let's start the
test examples with a simple GET request.

.. request:: A simple get

   GET /foo
.. 

You can match on the whole response -- be sure to always include both
the full status line and headers:

.. response::
 
   200 Ok
   Content-type: text/plain

   Hello
..

Or just the content. Notice that multiple response blocks can be
compared against the same request.

.. response::

   Hello
..

The output comparison is done using a doctest OutputChecker. The
doctest extensions NORMALIZE_WHITESPACE and ELLIPSIS are always on, so
this response also matches:

.. response::

   200 ...
   ...

   He...o
..

----

POST requests include the data to be posted after the request line.

.. request:: A simple POST

   POST /foo
   a=1&amp;b=2
..

The simple application used in this self test always responds to POST
requests by echoing back the posted parameters:

.. response::

   You said: a=1 and b=2
..

Just like with GETs, you can match against headers and content or content only.

.. response::

   200 Ok
   Content-type: text/plain

   You said: a=1 and b=2
..

----

Fixture code may be run around a request.

.. request:: A special request requiring its own fixture.
   :setup: client.setup_special()
   :teardown: client.teardown_special()

   GET /special
..

.. response ::

   SPECIAL is set.
..

.. request:: Without the fixture
   
   GET /special
..

.. response::

   SPECIAL is not set.
..

----

A simple shell example.

.. shell :: echo &quot;Hello&quot;

   Hello
..

Source
~~~~~~

Here is the source of the fixtures file used with this test:

.. include:: about.py
   :literal:

And the source of the test document itself:

.. include:: about.rst
   :literal:
   
.. _`reStructured Text`: http://docutils.sourceforge.net/rst.html
.. _`paste.fixtures.TestApp` : http://pythonpaste.org/testing-applications.html
</pre>
</div>
</div>
</body>
</html>
